`timescale 1ns/1ps
`default_nettype none

module key_pattern #(
 parameter   [11:0] HBLANK = 1024,
 parameter   [11:0] VBLANK = 1024 ,
 parameter   [9:0]  MOVE_TIME = 10'd1000,
 parameter   [9:0]  LOST_TIME = 10'd1000  // 1000ms
)
(
    // system signal
    input  wire         I_sclk,  // 125M
    input  wire         I_rst_n,
    // key

    input  wire         I_key_in,        // 帧丢失后黑屏或者有按键

    input  wire [9:0]   ram_waddr_rgb,
    input  wire [31:0]  ram_wdata_rgb,
    input  wire         ram_wr_rgb,

    // time
    input  wire         I_time_1ms_sync,
    // config
    input  wire [10:0]  I_cfg_win_col_num,   // 带载列数（宽度）
    input  wire [10:0]  I_cfg_win_row_num,   // 带载行数（高度）
    input  wire         I_cfg_black_on_lost, // 丢失信号后黑屏
    // status
    output wire         O_status_key_en,
    output wire         O_frame_lost,
    // input  frame
    input  wire         I_frame_start,
    input  wire         I_frame_end,
    input  wire         I_row_end,
    input  wire         I_burst_start,
    input  wire [12:0]  I_burst_row,
    input  wire [12:0]  I_burst_col,
    input  wire         I_pixel_en,
    input  wire [7:0]   I_pixel_data,

    // output frame
    output reg          O_frame_start,
    output reg          O_frame_end,
    output reg          O_row_end,
    output reg          O_burst_start,
    output reg  [12:0]  O_burst_row,
    output reg  [12:0]  O_burst_col,
    output reg          O_pixel_en,
    output reg  [7:0]   O_pixel_data,
    
    output reg          kp_busy
);
//------------------------Parameter----------------------
// fsm
localparam [3:0]
    IDLE  = 0,
    START = 1,
    WAIT0 = 2,
    DAT_R = 3,
    DAT_G = 4,
    DAT_B = 5,
    LOOP  = 6,
    OVER  = 7,
    WAIT1 = 8;

//------------------------Local signal-------------------
// fsm
reg  [3:0]  state;
reg  [3:0]  next;
reg  [9:0]  x;
reg  [9:0]  y;
reg  [11:0] cnt;

// frame detect
reg         power_on;
reg         enable;
reg         frame_lost;
reg  [9:0]  lost_cnt;


//------------------------Instantiation------------------

//------------------------Body---------------------------

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        kp_busy <= 0;
    else begin
        kp_busy <= (  state != IDLE);
    end  
end

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        state <= IDLE;
    else 
    case (state)
        IDLE: begin
            if( I_key_in )
                state <= START;
            else 
                state <= IDLE;
        end

        START: begin
            state <= WAIT0;
        end

        WAIT0: begin
            if (cnt == HBLANK)
                state <= DAT_R;
            else
                state <= WAIT0;
        end

        DAT_R: begin
            state <= DAT_G;
        end

        DAT_G: begin
            state <= DAT_B;
        end

        DAT_B: begin
            if (x == I_cfg_win_col_num - 1'b1)
                state <= LOOP;
            else
                state <= DAT_R;
        end

        LOOP: begin
            if (y == I_cfg_win_row_num - 1'b1)
                state <= OVER;
            else
                state <= WAIT0;
        end

        OVER: begin
            state <= WAIT1;
        end

        WAIT1: begin
            // if (cnt == VBLANK)
            state <= IDLE;
        end

        default: begin
            state <= IDLE;
        end
    endcase
end

// x
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        x <= 1'b0;
    else if (state == WAIT0)
        x <= 1'b0;
    else if (state == DAT_B)
        x <= x + 1'b1;
end

// y
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        y <= 1'b0;
    else if (state == START)
        y <= 1'b0;
    else if (state == LOOP)
        y <= y + 1'b1;
end

// cnt
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        cnt <= 1'b1;
    else if (state == START || state == LOOP)
        cnt <= 1'b1;
    else
        cnt <= cnt + 1'b1;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++frame detect+++++++++++++++++++
// power_on
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        power_on <= 1'b1;
    else if (I_frame_start)
        power_on <= 1'b0;
    else if ( I_key_in )
        power_on <= 1'b0;
end

// enable
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        enable <= 1'b0;
    else if (power_on)
        enable <= 1'b0;
    else if (I_frame_start)
        enable <= 1'b0;
    else if ( I_key_in )
        enable <= 1'b1;
end

// frame_lost
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        frame_lost <= 1'b0;
    else if (I_frame_start)
        frame_lost <= 1'b0;
    else if ( I_key_in )
        frame_lost <= 1'b1;
end
//{{{+++++++++++++++++++++output frame+++++++++++++++++++
// O_frame_start
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_frame_start <= 1'b0;
    else if (~enable)
        O_frame_start <= I_frame_start;
    else if (state == START)
        O_frame_start <= 1'b1;
    else
        O_frame_start <= 1'b0;
end

// O_frame_end
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_frame_end <= 1'b0;
    else if (~enable)
        O_frame_end <= I_frame_end;
    else
        O_frame_end <= (state == OVER);
end

// O_row_end
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_row_end <= 1'b0;
    else if (~enable)
        O_row_end <= I_row_end;
    else if (state == LOOP)
        O_row_end <= 1'b1;
    else
        O_row_end <= 1'b0;
end

// // O_burst_start
// always @(posedge I_sclk or negedge I_rst_n) begin
    // if (~I_rst_n)
        // O_burst_start <= 1'b0;
    // else if (~enable)
        // O_burst_start <= I_burst_start;
    // else if (state == WAIT0 && next == DAT_R)
        // O_burst_start <= 1'b1;
    // else
        // O_burst_start <= 1'b0;
// end

// O_burst_start
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_burst_start <= 1'b0;
    else if (~enable)
        O_burst_start <= I_burst_start;
    else if (state == WAIT0 && cnt == HBLANK)
        O_burst_start <= 1'b1;
    else
        O_burst_start <= 1'b0;
end


// O_pixel_en
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_pixel_en <= 1'b0;
    else if (~enable)
        O_pixel_en <= I_pixel_en;
    else if (state == DAT_R || state == DAT_G || state == DAT_B)
        O_pixel_en <= 1'b1;
    else
        O_pixel_en <= 1'b0;
end

// O_burst_row
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_burst_row <= 1'b0;
    else if (~enable)
        O_burst_row <= I_burst_row;
    else
        O_burst_row <= y;
end

// O_burst_col
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_burst_col <= 1'b0;
    else if (~enable)
        O_burst_col <= I_burst_col;
    else
        O_burst_col <= 1'b0;
end

//{{{+++++++++++++++++++++status+++++++++++++++++++++++++
assign O_status_key_en = enable;
assign O_frame_lost    = frame_lost;
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++


reg [9:0]ram_raddr_rgb;
wire [7:0]ram_rdata_rgb;
// reg ram_rst;
 // sdpram_256x96
sdram_256x32_1024x8 ram_rgb (
    // .aclr       ( 1'b0 ), //( ram_rst ),
    .data       ( ram_wdata_rgb[31:0] ),
    .rdaddress  ( ram_raddr_rgb[9:0] ),
    .clock      ( I_sclk ),
    // .rden      ( ram_rd_rgb ),
    .wraddress  ( ram_waddr_rgb[9:2] ),
    .wren       ( ram_wr_rgb ),
    .q          ( ram_rdata_rgb[7:0] )
);

// sdpram_lpm #(
    // .A_ADDRESS_WIDTH    (   8   ),
    // .A_DATA_WIDTH       (   32  ),
    // .B_ADDRESS_WIDTH    (   10  ),
    // .B_DATA_WIDTH       (   8   )
    // )
// ram_rgb(
    // .clka       (   I_sclk                  ),
    // .wea        (   ram_wr_rgb              ),
    // .addra      (   ram_waddr_rgb[9:2]      ),
    // .dina       (   ram_wdata_rgb[31:0]     ),

    // .clkb       (   I_sclk                  ),
    // .reb        (   1'b1/*ram_rd_rgb*/              ),
    // .addrb      (   ram_raddr_rgb[9:0]      ),
    // .doutb      (   ram_rdata_rgb[7:0]      )
    
// );


always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_pixel_data <= 1'b0;
    else if (~enable)
        O_pixel_data <= I_pixel_data;
    else begin
        O_pixel_data <= ram_rdata_rgb;
    end
end

always  @(posedge I_sclk or negedge I_rst_n) begin
    if(!I_rst_n)begin
        ram_raddr_rgb[1:0] <= 0;
    end
    else if ( (state == WAIT0 && cnt == HBLANK) || state == DAT_R || state == DAT_B )
         ram_raddr_rgb[1:0] <=  ram_raddr_rgb[1:0] +1;
    else if( state == DAT_G  || state == LOOP || state == START)
        ram_raddr_rgb[1:0] <= 0;
end

always  @(posedge I_sclk or negedge I_rst_n) begin
    if(!I_rst_n)begin
        ram_raddr_rgb[9:2] <= 0;
    end
    else if(state == WAIT0 )begin
        ram_raddr_rgb[5:2] <= 0 ;
        ram_raddr_rgb[9:6] <= y[3:0] ;
    end
    else if ( state == DAT_G )begin
        ram_raddr_rgb[5:2] <= ram_raddr_rgb[5:2] + 1;
    end
end

endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
